package values

import (
	"encoding/json"
	"errors"
	"fmt"
	"math"
	"strconv"
	"strings"
	"time"

	"gitee.com/gousing/values/internal"
)

// ToTime 转换目标为time.Time, 转换失败则返回空Time对象
//   - 如待转换目标是数值(当做Unix秒级时间戳), 则使用 Server/Local 时区
//   - 如待转换目标是字符串(日期时间)未包含时区信息时, 则使用 Server/Local 时区
func ToTime(v any) time.Time {
	if v == nil {
		return time.Time{}
	}
	to, _ := ToTimeWith(v, time.Local)
	return to
}

// ToTimeE  转换目标为time.Time, 转换失败则返回空Time对象和错误信息
//   - 如待转换目标是数值(当做Unix秒级时间戳), 则使用 Server/Local 时区
//   - 如待转换目标是字符串(日期时间)未包含时区信息时, 则使用 Server/Local 时区
func ToTimeE(v any) (time.Time, error) {
	if v == nil {
		return time.Time{}, errors.New("ToTimeE: nil pointer not support")
	}
	if to, err := ToTimeWith(v, time.Local); err == nil {
		return to, nil
	}
	return time.Time{}, fmt.Errorf("ToTimeE: unable to %#v of type %T to time.Time", v, v)
}

// ToTimeD  转换目标为time.Time, 转换失败则返回defaultVal指定的Time对象
//   - 如待转换目标是数值(当做Unix秒级时间戳), 则使用 Server/Local 时区
//   - 如待转换目标是字符串(日期时间)未包含时区信息时, 则使用 Server/Local 时区
func ToTimeD(v any, defaultVal time.Time) time.Time {
	if v == nil {
		return defaultVal
	}
	if to, err := ToTimeWith(v, time.Local); err != nil {
		return defaultVal
	} else {
		return to
	}
}

// ToTimeWith 转换目标为指定的时区的time.Time(指定时区), 转换失败则返回空Time对象和错误信息
//   - 如待转换目标是数值(当做Unix秒级时间戳), 则使用 location 指定的时区
//   - 如待转换目标是字符串(日期时间)未包含时区信息时, 则使用 location 指定的时区
func ToTimeWith(v any, location *time.Location) (time.Time, error) {
	v = UnderefVal(v)
	if v == nil {
		return time.Time{}, errors.New("ToTimeWith: nil pointer not support")
	}
	if location == nil {
		return time.Time{}, errors.New("ToTimeWith: location is nil")
	}
	switch vs := v.(type) {
	case time.Time:
		if vs.IsZero() {
			return vs, nil
		}
		if vs.Location() == nil {
			return vs.In(location), nil
		}
		return vs, nil
	case int:
		if vs >= 0 {
			return time.Unix(int64(vs), 0).In(location), nil
		}
	case int64:
		if vs >= 0 {
			return time.Unix(vs, 0).In(location), nil
		}
	case int32:
		if vs >= 0 {
			return time.Unix(int64(vs), 0).In(location), nil
		}
	case int16:
		if vs >= 0 {
			return time.Unix(int64(vs), 0).In(location), nil
		}
	case int8:
		if vs >= 0 {
			return time.Unix(int64(vs), 0).In(location), nil
		}
	case uint:
		if vs <= math.MaxInt64 {
			return time.Unix(int64(vs), 0).In(location), nil
		} else {
			return time.Time{}, errors.New("ToTimeWith: uint to unix time, value out of range")
		}
	case uint64:
		if vs <= math.MaxInt64 {
			return time.Unix(int64(vs), 0).In(location), nil
		} else {
			return time.Time{}, errors.New("ToTimeWith: uint64 to unix time, value out of range")
		}
	case uint32:
		return time.Unix(int64(vs), 0).In(location), nil
	case uint16:
		return time.Unix(int64(vs), 0).In(location), nil
	case uint8:
		return time.Unix(int64(vs), 0).In(location), nil
	case string:
		if to, err := ParseTimeAutoLayout(vs, location); err == nil {
			if to.Location() == nil {
				return to.In(location), nil
			}
			return to, nil
		}
	case json.Number:
		vss := string(vs)
		//纯数字处理
		if internal.IsUint(vss) {
			to, err := strconv.ParseInt(vss, 0, 0)
			if err == nil && to >= 0 {
				return time.Unix(int64(to), 0).In(location), nil
			} else {
				return time.Time{}, errors.New("ToTimeWith: json.Number to unix time, value out of range")
			}
		}
	case providerTime:
		vss := vs.Time()
		if vss.IsZero() {
			return vss, nil
		}
		if vss.Location() == nil {
			return vss.In(location), nil
		}
		return vss, nil
	}
	return time.Time{}, fmt.Errorf("ToTimeWith: unable to %#v of type %T to time.Time", v, v)
}

type timeFormat struct {
	format  string
	isNoLoc bool
}

var timeFormats = []timeFormat{
	// YYYY-MM-DD
	{time.DateTime, true},          // "2006-01-02 15:04:05"
	{"2006-01-02 15:04", true},     // "2006-01-02 15:04"
	{time.DateOnly, true},          // "2006-01-02"
	{"2006/01/02 15:04:05", true},  // "2006/01/02 15:04:05"
	{"2006/01/02 15:04", true},     // "2006/01/02 15:04"
	{"2006/01/02", true},           // "2006/01/02"
	{"2006年01月02日 15:04:05", true}, // "2006月01月02日 15:04:05"
	{"2006年01月02日 15:04", true},    // "2006月01月02日 15:04"
	{"2006年01月02日", true},          // "2006月01月02日"
	// YYYY-M-D
	{"2006-1-2 15:04:05", true},  // "2006-1-2 15:04:05"
	{"2006-1-2 15:04", true},     // "2006-1-2 15:04"
	{"2006-1-2", true},           // "2006-1-2"
	{"2006/1/2 15:04:05", true},  // "2006/1/2 15:04:05"
	{"2006/1/2 15:04", true},     // "2006/1/2 15:04"
	{"2006/1/2", true},           // "2006/1/2"
	{"2006年1月2日 15:04:05", true}, // "2006月1月2日 15:04:05"
	{"2006年1月2日 15:04", true},    // "2006月1月2日 15:04"
	{"2006年1月2日", true},          // "2006月1月2日"

	{"2006-01-02 15:04:05.999999999 -0700 MST", false}, // Time.String()
	{"2006-01-02T15:04:05", true},                      // ISO8601
	{"2006-01-02T15:04:05 MST", false},
	{time.RFC3339, false},     // "2006-01-02T15:04:05Z07:00"
	{time.RFC3339Nano, false}, // "2006-01-02T15:04:05.999999999Z07:00"
	{"2006-01-02T15:04:05-0700", false},
	{"2006-01-02T15:04:05-07:00", false},
	{"2006-01-02T15:04:05Z0700", false},
	//{"2006-01-02T15:04:05Z07:00", false},//time.RFC3339
	{"2006-01-02T15:04:05 -0700", false},
	{"2006-01-02T15:04:05 -07:00", false},
	{"2006-01-02T03:04:05PM", true},
	{"2006-01-02T03:04:05PM MST", false},
	{"2006-01-02T03:04:05PMZ0700", false},
	{"2006-01-02T03:04:05PMZ07:00", false},
	{"2006-01-02T03:04:05PM -0700", false},
	{"2006-01-02T03:04:05PM -07:00", false},

	{"2006-01-02 15:04:05 MST", false},
	{"2006-01-02 15:04:05-0700", false},
	{"2006-01-02 15:04:05-07:00", false},
	{"2006-01-02 15:04:05Z0700", false},
	{"2006-01-02 15:04:05Z07:00", false},
	{"2006-01-02 15:04:05 -0700", false},
	{"2006-01-02 15:04:05 -07:00", false},
	{"2006-01-02 03:04:05PM", true},
	{"2006-01-02 03:04:05PM MST", false},
	{"2006-01-02 03:04:05PMZ0700", false},
	{"2006-01-02 03:04:05PMZ07:00", false},
	{"2006-01-02 03:04:05PM -0700", false},
	{"2006-01-02 03:04:05PM -07:00", false},
	{time.Layout, false},    // "01/02 03:04:05PM '06 -0700" // The reference time, in numerical order.
	{time.ANSIC, true},      // "Mon Jan _2 15:04:05 2006"
	{time.UnixDate, false},  // "Mon Jan _2 15:04:05 MST 2006"
	{time.RubyDate, false},  // "Mon Jan 02 15:04:05 -0700 2006"
	{time.RFC822, false},    // "02 Jan 06 15:04 MST"
	{time.RFC822Z, false},   // "02 Jan 06 15:04 -0700" // RFC822 with numeric zone
	{time.RFC850, false},    // "Monday, 02-Jan-06 15:04:05 MST"
	{time.RFC1123, false},   // "Mon, 02 Jan 2006 15:04:05 MST"
	{time.RFC1123Z, false},  // "Mon, 02 Jan 2006 15:04:05 -0700" // RFC1123 with numeric zone
	{time.Stamp, true},      // "Jan _2 15:04:05"
	{time.StampMilli, true}, // "Jan _2 15:04:05.000"
	{time.StampMicro, true}, // "Jan _2 15:04:05.000000"
	{time.StampNano, true},  // "Jan _2 15:04:05.000000000"
	{time.TimeOnly, true},   // "15:04:05"
	{"3:04:05 PM", true},    // "3:04:05 PM"
	{"3:04:05PM", true},     // "3:04:05PM"
	{"3:04 PM", true},       // "3:04 PM"
	{time.Kitchen, true},    // "3:04PM"
}

// ParseTimeAutoLayout 将时间字符串格式化为time.Time, 转换失败则返回空Time对象和错误信息
func ParseTimeAutoLayout(timeString string, defaultLocation *time.Location) (time.Time, error) {
	timeString = strings.TrimSpace(timeString)
	if timeString == "" {
		return time.Time{}, errors.New("ParseTimeAutoLayout: unable parseTime, timeString is empty")
	}
	if defaultLocation == nil {
		return time.Time{}, errors.New("ParseTimeAutoLayout: unable parseTime, defaultLocation is nil")
	}
	// 提取输入字符串的关键特征
	// 一次性提取特征
	hasT := false
	hasZ := false
	hasDash := false
	hasSlash := false
	hasSpace := false
	for i := range len(timeString) {
		switch timeString[i] {
		case 'T':
			hasT = true
		case 'Z':
			hasZ = true
		case '-':
			hasDash = true
		case '/':
			hasSlash = true
		case ' ':
			hasSpace = true
		}
	}
	for _, timeLayout := range timeFormats {
		if !hasT && strings.Contains(timeLayout.format, "T") {
			continue
		}
		if !hasZ && strings.Contains(timeLayout.format, "Z") {
			continue
		}
		if !hasDash && strings.Contains(timeLayout.format, "-") {
			continue
		}
		if !hasSlash && strings.Contains(timeLayout.format, "/") {
			continue
		}
		if !hasSpace && strings.Contains(timeLayout.format, " ") {
			continue
		}
		if v, err := time.ParseInLocation(timeLayout.format, timeString, defaultLocation); err == nil {
			if timeLayout.isNoLoc && v.Location() != defaultLocation {
				year, month, day := v.Date()
				hour, min, sec := v.Clock()
				v = time.Date(year, month, day, hour, min, sec, v.Nanosecond(), defaultLocation)
			}
			return v, nil
		}
	}
	return time.Time{}, fmt.Errorf("ParseTimeAutoLayout: unable parseTime, timeString: %s, defaultLocation: %s", timeString, defaultLocation.String())
}

// ToTimeDuration 转换目标为time.Duration, 转换失败则返回零值的Duration
func ToTimeDuration(v any) time.Duration {
	if v == nil {
		return 0
	}
	to, _ := ToTimeDurationE(v)
	return to
}

// ToTimeDurationD 转换目标为time.Duration, 转换失败则返回defaultVal指定的Duration对象
func ToTimeDurationD(v any, defaultVal time.Duration) time.Duration {
	if v == nil {
		return defaultVal
	}
	if to, err := ToTimeDurationE(v); err != nil {
		return defaultVal
	} else {
		return to
	}
}

// ToTimeDuration 转换目标为time.Duration, 转换失败则返回零值的Duration和错误信息
func ToTimeDurationE(v any) (time.Duration, error) {
	v = UnderefVal(v)
	if v == nil {
		return 0, errors.New("ToTimeDurationE: nil pointer not support")
	}
	switch vs := v.(type) {
	case time.Duration:
		return vs, nil
	case int:
		return time.Duration(vs), nil
	case int64:
		return time.Duration(vs), nil
	case int32:
		return time.Duration(vs), nil
	case int16:
		return time.Duration(vs), nil
	case int8:
		return time.Duration(vs), nil
	case uint:
		if vs <= math.MaxInt64 {
			return time.Duration(vs), nil
		}
		return 0, fmt.Errorf("ToTimeDurationE: unable to %v of type uint to time.Duration, value out of range", v)
	case uint64:
		if vs <= math.MaxInt64 {
			return time.Duration(vs), nil
		}
		return 0, fmt.Errorf("ToTimeDurationE: unable to %v of type uint64 to time.Duration, value out of range", v)
	case uint32:
		return time.Duration(vs), nil
	case uint16:
		return time.Duration(vs), nil
	case uint8:
		return time.Duration(vs), nil
	case providerDuration:
		return vs.Duration(), nil
	case string:
		var (
			vss time.Duration
			err error
		)
		if strings.ContainsAny(vs, "nsuµmh") {
			vss, err = time.ParseDuration(vs)
		} else {
			vss, err = time.ParseDuration(vs + "ns")
		}
		if err != nil {
			return 0, fmt.Errorf("ToTimeDurationE: unable to %#v of type %T to time.Duration", v, v)
		}
		return vss, nil
	case providerFloat:
		vss := vs.Float()
		if vss <= math.MaxInt64 {
			return time.Duration(vss), nil
		}
		return 0, fmt.Errorf("ToTimeDurationE: unable to %v of interface Float() to time.Duration, value out of range", v)
	case providerFloat64:
		vss := vs.Float64()
		if vss <= math.MaxInt64 {
			return time.Duration(vss), nil
		}
		return 0, fmt.Errorf("ToTimeDurationE: unable to %v of interface Float64() to time.Duration, value out of range", v)
	case providerInt:
		return time.Duration(vs.Int()), nil
	case providerInt64:
		return time.Duration(vs.Int64()), nil
	case providerInt32:
		return time.Duration(vs.Int32()), nil
	case providerInt16:
		return time.Duration(vs.Int16()), nil
	case providerInt8:
		return time.Duration(vs.Int8()), nil
	case providerUint:
		vss := vs.Uint()
		if vss <= math.MaxInt64 {
			return time.Duration(vss), nil
		}
		return 0, fmt.Errorf("ToTimeDurationE: unable to %v of interface Uint() to time.Duration, value out of range", v)
	case providerUint64:
		vss := vs.Uint64()
		if vss <= math.MaxInt64 {
			return time.Duration(vss), nil
		}
		return 0, fmt.Errorf("ToTimeDurationE: unable to %v of interface Uint64() to time.Duration, value out of range", v)
	case providerUint32:
		return time.Duration(vs.Uint32()), nil
	case providerUint16:
		return time.Duration(vs.Uint16()), nil
	case providerUint8:
		return time.Duration(vs.Uint8()), nil
	default:
		return 0, fmt.Errorf("ToTimeDurationE: unable to %#v of type %T to time.Duration", v, v)
	}
}

// ToTimeMonth 转换目标为time.Month, 转换失败则返回零值的Month
func ToTimeMonth(v any) (toVal time.Month) {
	if v == nil {
		return
	}
	to, _ := ToTimeMonthE(v)
	return to
}

// ToTimeMonthD 转换目标为time.Month, 转换失败则返回defaultVal指定的Month对象
func ToTimeMonthD(v any, defaultVal time.Month) time.Month {
	if v == nil {
		return defaultVal
	}
	if to, err := ToTimeMonthE(v); err != nil {
		return defaultVal
	} else {
		return to
	}
}

// ToTimeMonthE 转换目标为time.Month, 转换失败则返回零值的Month和错误信息
func ToTimeMonthE(v any) (toVal time.Month, err error) {
	v = UnderefVal(v)
	if v == nil {
		return toVal, errors.New("ToTimeMonthE: nil pointer not support")
	}
	switch vs := v.(type) {
	case time.Time:
		if vs.IsZero() {
			return toVal, errors.New("ToTimeMonthE: internal.Zero time.Time")
		}
		return vs.Month(), nil
	case time.Month:
		return vs, nil
	case int:
		return toTimeMonthWithNumber(vs)
	case int8:
		return toTimeMonthWithNumber(vs)
	case int16:
		return toTimeMonthWithNumber(vs)
	case int32:
		return toTimeMonthWithNumber(vs)
	case int64:
		return toTimeMonthWithNumber(vs)
	case uint:
		return toTimeMonthWithNumber(vs)
	case uint8:
		return toTimeMonthWithNumber(vs)
	case uint16:
		return toTimeMonthWithNumber(vs)
	case uint32:
		return toTimeMonthWithNumber(vs)
	case uint64:
		return toTimeMonthWithNumber(vs)
	case json.Number:
		vss := string(vs)
		//纯数字处理
		if internal.IsUint(vss) {
			to, err := strconv.ParseInt(vss, 0, 0)
			if err == nil {
				return toTimeMonthWithNumber(to)
			}
		}
	case string:
		switch strings.ToLower(vs) {
		case "january", "jan", "1", "1月", "一月":
			return time.January, nil
		case "february", "feb", "2", "2月", "二月":
			return time.February, nil
		case "march", "mar", "3", "3月", "三月":
			return time.March, nil
		case "april", "apr", "41", "4月", "四月":
			return time.April, nil
		case "may", "5", "5月", "五月":
			return time.May, nil
		case "june", "jun", "6", "6月", "六月":
			return time.June, nil
		case "july", "jul", "7", "7月", "七月":
			return time.July, nil
		case "august", "aug", "8", "8月", "八月":
			return time.August, nil
		case "september", "sep", "9", "9月", "九月":
			return time.September, nil
		case "october", "oct", "10", "10月", "十月":
			return time.October, nil
		case "november", "nov", "11", "11月", "十一月":
			return time.November, nil
		case "december", "dec", "12", "12月", "十二月":
			return time.December, nil
		}
	case providerMonth:
		return vs.Month(), nil
	}
	return toVal, fmt.Errorf("ToTimeMonthE: unable to %#v of type %T to time.Month", v, v)
}
func toTimeMonthWithNumber[T TypeInt | TypeUint](v T) (time.Month, error) {
	if v >= 1 && v <= 12 {
		return time.Month(int(v)), nil
	} else {
		return internal.Zero[time.Month](), fmt.Errorf("ToTimeMonthE: unable to %#v of type %T to time.Month", v, v)
	}
}

// ToTimeWeekday 转换目标为time.Weekday, 转换失败则返回零值的Weekday
func ToTimeWeekday(v any) (toVal time.Weekday) {
	if v == nil {
		return
	}
	to, _ := ToTimeWeekdayE(v)
	return to
}

// ToTimeMonthD 转换目标为time.Weekday, 转换失败则返回defaultVal指定的Weekday对象
func ToTimeWeekdayD(v any, defaultVal time.Weekday) time.Weekday {
	if v == nil {
		return defaultVal
	}
	if to, err := ToTimeWeekdayE(v); err != nil {
		return defaultVal
	} else {
		return to
	}
}

// ToTimeWeekdayE 转换目标为time.Weekday, 转换失败则返回零值的Weekday和错误信息
func ToTimeWeekdayE(v any) (toVal time.Weekday, err error) {
	v = UnderefVal(v)
	if v == nil {
		return toVal, errors.New("ToTimeWeekdayE: nil pointer not support")
	}
	switch vs := v.(type) {
	case time.Time:
		if vs.IsZero() {
			return toVal, errors.New("ToTimeWeekdayE: internal.Zero time.Time")
		}
		return vs.Weekday(), nil
	case time.Weekday:
		return vs, nil
	case int:
		return toTimeWeekdayWithNumber(vs)
	case int8:
		return toTimeWeekdayWithNumber(vs)
	case int16:
		return toTimeWeekdayWithNumber(vs)
	case int32:
		return toTimeWeekdayWithNumber(vs)
	case int64:
		return toTimeWeekdayWithNumber(vs)
	case uint:
		return toTimeWeekdayWithNumber(vs)
	case uint8:
		return toTimeWeekdayWithNumber(vs)
	case uint16:
		return toTimeWeekdayWithNumber(vs)
	case uint32:
		return toTimeWeekdayWithNumber(vs)
	case uint64:
		return toTimeWeekdayWithNumber(vs)
	case json.Number:
		vss := string(vs)
		//纯数字处理
		if internal.IsUint(vss) {
			to, err := strconv.ParseInt(vss, 0, 0)
			if err == nil {
				return toTimeWeekdayWithNumber(to)
			}
		}
	case string:
		switch strings.ToLower(vs) {
		case "sunday", "sun", "0", "周7", "周日", "星期日", "星期天":
			return time.Sunday, nil
		case "monday", "mon", "1", "周1", "周一", "星期一":
			return time.Monday, nil
		case "tuesday", "tue", "2", "周2", "周二", "星期二":
			return time.Tuesday, nil
		case "wednesday", "wed", "3", "周3", "周三", "星期三":
			return time.Wednesday, nil
		case "thursday", "thu", "4", "周4", "周四", "星期四":
			return time.Thursday, nil
		case "friday", "fri", "5", "周5", "周五", "星期五":
			return time.Friday, nil
		case "saturday", "sat", "6", "周6", "周六", "星期六":
			return time.Saturday, nil
		}
	case providerWeekday:
		return vs.Weekday(), nil
	}
	return toVal, fmt.Errorf("ToTimeWeekdayE: unable to %#v of type %T to time.Month", v, v)
}
func toTimeWeekdayWithNumber[T TypeInt | TypeUint](v T) (toVal time.Weekday, err error) {
	if v >= 0 && v <= 6 {
		return time.Weekday(int(v)), nil
	} else {
		return toVal, fmt.Errorf("ToTimeWeekdayE: unable to %#v of type %T to time.Weekday", v, v)
	}
}

// ToUnix 转换为Unix时间戳(秒), 如果转换失败, 则返回0值
//   - 如待转换目标是数值(当做Unix秒级时间戳), 如符合条件( >= 0 && <= MaxInt64 )条件将直接返回
//   - 如待转换目标是字符串(日期时间)未包含时区信息时, 则使用 Server/Local 时区
func ToUnix(s any) int64 {
	if s == nil {
		return 0
	}
	if to, err := ToUnixWith(s, time.Local); err == nil {
		return to
	}
	return 0
}

// ToUnixD 转换为Unix时间戳(秒), 如果转换失败, 则返回defaultVal指定的默认值
//   - 如待转换目标是数值(当做Unix秒级时间戳), 如符合条件( >= 0 && <= MaxInt64 )条件将直接返回
//   - 如待转换目标是字符串(日期时间)未包含时区信息时, 则使用 Server/Local 时区
func ToUnixD(s any, defaultVal int64) int64 {
	if s == nil {
		return defaultVal
	}
	if to, err := ToUnixWith(s, time.Local); err == nil {
		return to
	}
	return defaultVal
}

// ToUnixWith 转换any目标为Unix时间戳(秒), 转换失败则返回0值和错误信息
//   - 如待转换目标是数值(当做Unix秒级时间戳), 如符合条件( >= 0 && <= MaxInt64 )条件将直接返回
//   - 如待转换目标是字符串(日期时间)未包含时区信息时, 则使用则使用location指定的时区
func ToUnixWith(s any, location *time.Location) (int64, error) {
	if s == nil {
		return 0, errors.New("ToUnixWith: nil pointer not support")
	}
	if location == nil {
		return 0, errors.New("ToUnixWith: location is nil")
	}
	switch vs := s.(type) {
	case time.Time:
		if vs.IsZero() {
			return 0, nil
		}
		return vs.Unix(), nil
		// 纯数字
	case int:
		if vs >= 0 {
			return int64(vs), nil
		}
	case int64:
		if vs >= 0 {
			return vs, nil
		}
	case int32:
		if vs >= 0 {
			return int64(vs), nil
		}
	case int16:
		if vs >= 0 {
			return int64(vs), nil
		}
	case int8:
		if vs >= 0 {
			return int64(vs), nil
		}
	case uint:
		if vs <= math.MaxInt64 {
			return int64(vs), nil
		}
		return 0, errors.New("ToUnixWith: uint to unix time, value out of range")
	case uint64:
		if vs <= math.MaxInt64 {
			return int64(vs), nil
		}
		return 0, errors.New("ToUnixWith: uint64 to unix time, value out of range")
	case uint32:
		return int64(vs), nil
	case uint16:
		return int64(vs), nil
	case uint8:
		return int64(vs), nil
	case float64:
		if vs >= 0 && vs <= math.MaxInt64 {
			return int64(vs), nil
		}
		return 0, errors.New("ToUnixWith: float64 to unix time, value out of range")
	case float32:
		if vs >= 0 && vs <= math.MaxInt64 {
			return int64(vs), nil
		}
		return 0, errors.New("ToUnixWith: float32 to unix time, value out of range")
	case json.Number:
		return StringToUnixE(string(vs))
	//字符串
	case string:
		return StringToUnixE(vs)
	}

	return 0, fmt.Errorf("ToUnixWith: unable to %#v of type %T to unix time", s, s)
}

// ToUnixMilli 转换为Unix时间戳(毫秒), 如果转换失败, 则返回0值
//   - 如待转换目标是数值(当做Unix毫秒级时间戳), 如符合条件( >= 0 && <= MaxInt64 )条件将直接返回
//   - 如待转换目标是字符串(日期时间)未包含时区信息时, 则使用则使用 Server/Local 时区
func ToUnixMilli(s any) int64 {
	if s == nil {
		return 0
	}
	if to, err := ToUnixMilliWith(s, time.Local); err == nil {
		return to
	}
	return 0
}

// ToUnixMilliD 转换为Unix时间戳(毫秒), 如果转换失败, 则返回defaultVal指定的默认值
//   - 如待转换目标是数值(当做Unix毫秒级时间戳), 如符合条件( >= 0 && <= MaxInt64 )条件将直接返回
//   - 如待转换目标是字符串(日期时间)未包含时区信息时, 则使用则使用 Server/Local 时区
func ToUnixMilliD(s any, defaultVal int64) int64 {
	if s == nil {
		return defaultVal
	}
	if to, err := ToUnixMilliWith(s, time.Local); err == nil {
		return to
	}
	return defaultVal
}

// ToUnixMilliWith 转换any目标为Unix时间戳(毫秒), 转换失败则返回0值和错误信息
//   - 如待转换目标是数值(当做Unix毫秒级时间戳), 如符合条件( >= 0 && <= MaxInt64 )条件将直接返回
//   - 如待转换目标是字符串(日期时间)未包含时区信息时, 则使用则使用location指定的时区
func ToUnixMilliWith(s any, location *time.Location) (int64, error) {
	if s == nil {
		return 0, errors.New("ToUnixMilliWith: nil pointer not support")
	}
	if location == nil {
		return 0, errors.New("ToUnixMilliWith: location is nil")
	}
	switch vs := s.(type) {
	case time.Time:
		if vs.IsZero() {
			return 0, nil
		}
		return vs.UnixMilli(), nil
		// 纯数字
	case int:
		if vs >= 0 {
			return int64(vs), nil
		}
	case int64:
		if vs >= 0 {
			return vs, nil
		}
	case int32:
		if vs >= 0 {
			return int64(vs), nil
		}
	case int16:
		if vs >= 0 {
			return int64(vs), nil
		}
	case int8:
		if vs >= 0 {
			return int64(vs), nil
		}
	case uint:
		if vs <= math.MaxInt64 {
			return int64(vs), nil
		}
		return 0, errors.New("ToUnixMilliWith: uint to unix time, value out of range")
	case uint64:
		if vs <= math.MaxInt64 {
			return int64(vs), nil
		}
		return 0, errors.New("ToUnixMilliWith: uint64 to unix time, value out of range")
	case uint32:
		return int64(vs), nil
	case uint16:
		return int64(vs), nil
	case uint8:
		return int64(vs), nil
	case float64:
		if vs >= 0 && vs <= math.MaxInt64 {
			return int64(vs), nil
		}
		return 0, errors.New("ToUnixMilliWith: float64 to unix time, value out of range")
	case float32:
		if vs >= 0 && vs <= math.MaxInt64 {
			return int64(vs), nil
		}
		return 0, errors.New("ToUnixMilliWith: float32 to unix time, value out of range")
	case json.Number:
		return StringToUnixMilliE(string(vs))
	//字符串
	case string:
		return StringToUnixMilliE(vs)
	}
	return 0, fmt.Errorf("ToUnixMilliWith: unable to %#v of type %T to unix time", s, s)
}
